use std::path::Path;
use std::{fs, io};
use tauri::{AppHandle, Manager};
#[tauri::command]
fn greet(name: Vec<&str>) -> String {
    format!(
        "Hello, {}! You've been greeted from Rust!,{}",
        name[0], name[1]
    )
}
// 定义FFmpeg路径
const FFMPEG_PATH: &str = "resources/ffmpeg/ffmpeg";
#[tauri::command]
async fn mp4_to_png(app_handle: AppHandle, buffer: Vec<u8>) -> Result<String, tauri::Error> {
    let mut work_dir: std::path::PathBuf = app_handle.path().app_data_dir().unwrap();
    work_dir.push("mp4ToPng");

    let mut input_file_path = work_dir.clone();
    input_file_path.push("input");
    if !input_file_path.exists() {
        fs::create_dir_all(input_file_path.as_path())?;
    }
    input_file_path.push("input.mp4");
    fs::write(input_file_path.as_path(), buffer)?;
    // println!("{}", input_file_path.to_str().unwrap());
    let mut out_dir = work_dir.clone();
    out_dir.push("out");
    // println!("{}\\%04d.png", out_dir.to_str().unwrap());
    if !out_dir.exists() {
        fs::create_dir_all(out_dir.as_path())?;
    }
    clear_dir_contents(out_dir.to_str().unwrap())?;

    export_video_frames(input_file_path.to_str().unwrap(), out_dir.to_str().unwrap())
        .await
        .unwrap();
    Ok(out_dir.to_str().unwrap().to_string())
}

#[tauri::command]
async fn img_to_video(
    app_handle: AppHandle,
    buffers: Vec<Vec<u8>>,
    fps: u32,
    out_path: String,
) -> Result<(), tauri::Error> {
    let mut work_dir: std::path::PathBuf = app_handle.path().app_data_dir().unwrap();
    work_dir.push("img_to_video");

    let mut input_file_path = work_dir.clone();
    input_file_path.push("input");
    if !input_file_path.exists() {
        fs::create_dir_all(input_file_path.as_path())?;
    }
    for (i, buffer) in buffers.iter().enumerate() {
        let mut file_path = input_file_path.clone();
        file_path.push(format!("{}.png", i));
        tokio::fs::write(file_path.as_path(), buffer).await?;
    }
    let out_path_p = Path::new(&out_path);
    if out_path_p.exists() {
        fs::remove_file(out_path_p)?;
    }
    frames_export_video(input_file_path.to_str().unwrap(), &out_path, fps)
        .await
        .unwrap();
    Ok(())
}

#[tauri::command]
fn save_file_to_path(buffer: Vec<u8>, path: String) -> Result<(), tauri::Error> {
    fs::write(path, buffer)?;
    Ok(())
}

async fn frames_export_video(input_path: &str, out_path: &str, fps: u32) -> Result<(), String> {
    let fps_str = format!("{}", fps);
    let input_path = format!("{}/%d.png", input_path);

    let gif_args = format!(
        "fps={},split[s0][s1];[s0]palettegen=max_colors=128[p];[s1][p]paletteuse=dither=bayer",
        fps
    );
    let mut args: Vec<&str> = ["-r", &fps_str, "-f", "image2", "-i", &input_path, out_path].into();
    if out_path.ends_with(".gif") {
        args = [
            "-framerate",
            &fps_str,
            "-i",
            &input_path,
            "-vf",
            &gif_args,
            "-loop",
            "0",
            out_path,
        ]
        .into();
    }
    // println!("{}", args.join(" "));
    // let output = format!("{}/%04d.png", out_path);
    let status = tokio::process::Command::new(FFMPEG_PATH)
        .args(args)
        .creation_flags(0x08000000)
        .status()
        .await;
    if status.is_err() {
        return Err(("FFmpeg failed to process").into());
    };

    if status.unwrap().success() {
        Ok(())
    } else {
        Err(("FFmpeg failed to process").into())
    }
}

async fn export_video_frames(input_path: &str, output_dir: &str) -> Result<(), String> {
    let output = format!("{}/%04d.png", output_dir);
    let status = tokio::process::Command::new(FFMPEG_PATH)
        .args(["-i", &input_path, output.as_str()])
        .creation_flags(0x08000000)
        .status()
        .await;
    if status.is_err() {
        return Err(("FFmpeg failed to process").into());
    };

    if status.unwrap().success() {
        Ok(())
    } else {
        Err(("FFmpeg failed to process").into())
    }
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .plugin(tauri_plugin_dialog::init())
        .plugin(tauri_plugin_opener::init())
        .plugin(tauri_plugin_fs::init())
        .invoke_handler(tauri::generate_handler![
            greet,
            mp4_to_png,
            save_file_to_path,
            img_to_video
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

// 安全地删除目录内容但保留目录本身
fn clear_dir_contents(dir_path: &str) -> Result<(), io::Error> {
    let path = Path::new(dir_path);

    if !path.exists() {
        return Ok(());
    }

    if !path.is_dir() {
        return Err(io::Error::new(io::ErrorKind::InvalidInput, "路径不是目录"));
    }

    for entry in fs::read_dir(path)? {
        let entry = entry?;
        let entry_path = entry.path();

        if entry_path.is_dir() {
            fs::remove_dir_all(&entry_path)?;
            // println!("删除子目录: {:?}", entry_path);
        } else {
            fs::remove_file(&entry_path)?;
            // println!("删除文件: {:?}", entry_path);
        }
    }
    println!("成功清空目录内容: {}", dir_path);
    Ok(())
}
